Back to Main Menu

Assetic REST API Tutorial (Python)

The following examples expand on the Quick Start examples by providing more detail about how the Assetic Python SDK utilises the Assetic REST API. 

The Assetic Python SDK wraps each Assetic REST API endpoint in a python method.  These methods are in python classes that correspond to the API grouping evident when looking at the page https://your_site.assetic.net/apidocs.  Since the API's are RESTful, the URL of the api endpoints reflect this structure.  The names of these python classes are based on the name of the Assetic REST api endpoint grouping with the suffix 'Api'.  In the Quick Start example that is 'VersionApi'.

 

The Quick Start "Get Version" example above is a simple get without any parameters.  Many of the API's will however require parameters to be provided, usually as an object that has specific properties.  The Assetic Python SDK includes these object classes (class name typically prefixed with 'Assetic3IntegrationRepresentations').

 

A python IDE such as IDLE can be used to list the API methods and object classes.  The names will correspond with the endpoint names and model schema's in https://your_site.assetic.net/apidocs

 

This tutorial provides sample code for completing the following common tasks with the Assetic Python SDK:

Getting Data from Assetic using Assetic SDK

The following example gets the work order details for a given work order Id.  Note that the Id is a GUID string.

 

Replace the following placeholder in the script with your information:your_config_path.

 

To learn how the script works, see the inline comments (which start with # in Python) as well as the explanations that follow.

 

  1. """
  2. Example script to get work order using guid (Assetic.WorkOrderGetAPI.py)
  3. """
  4. import assetic
  5. ##Assetic SDK instance
  6. asseticsdk = assetic.AsseticSDK("C:/Users/sjsam/Documents/rest-api-examples/Python/assetic.ini",None,"Info")
  7. #instance of work order API
  8. wkoapi = assetic.WorkOrderApi()
  9. ##unique ID of work order
  10. woguid = "115ee90b-7ede-4e00-8ad2-0001f6646bab"
  11. try:
  12. wko = wkoapi.work_order_integration_api_get_0(woguid)
  13. except assetic.rest.ApiException as e:
  14. asseticsdk.logger.error("Status {0}, Reason: {1}".format(e.status,e.reason))
  15. else:
  16. ##output the response to the logger
  17. asseticsdk.logger.info(wko.get("WorkOrderStatus"))
  18. asseticsdk.logger.info(wko.get("FriendlyId"))

How it Works

The script first imports the assetic module.  Next it initiates the assetic instance by providing the location of the ini file ("/your_config_path/assetic.ini") containing the API Key and environment URL variables we defined in our "assetic.ini" file. These variables are used for authenticating the Assetic REST API queries.

The second parameter sets the logging output.  In this example it is "None", so the default is to log output to the console.  Alternatively a log file name (including folder path) could be set defined so that the logging is written to a text file.

The third parameter is the the debugging level for the logger which is set as "Info" in this example

import assetic ##Assetic SDK instance asseticsdk = assetic.AsseticSDK("/your_config_path/assetic.ini",None,"Info")

The next step in the script is to set the work order Id that will be searched and also create an instance of the work order API module.

#instance of work order API wkoapi = assetic.WorkOrderApi()  ##unique ID of work order woguid =  "115ee90b-7ede-4e00-8ad2-0001f6646bab"

Now that the work order API is configured, the method "work_order_get_0" can be used to retrieve the work order.  If there is an error the SDK will manage the error and package it as an exception of type assetic.rest.ApiException.  If there is no error the WorkOrderStatus and Friendly Id is extracted from the response and displayed to the console via the logger.  If there is an error the error message is displayed to the console via the logger.

try:     wko = wkoapi.work_order_get_0(woguid)  except assetic.rest.ApiException  as e:     asseticsdk.logger.error("Status {0}, Reason: {1}".format(e.status,e.reason))  else:  ##output the response to the logger     asseticsdk.logger.info(wko.get("WorkOrderStatus"))     asseticsdk.logger.info(wko.get("FriendlyId"))

Updating Data in Assetic using Assetic SDK

The following example updates the 'External Cost' for a task in a work order.

 

Before trying out the script, change the value of the id variable and replace the following placeholder: your_config_path.

 

The "assetic.ini" config file must be created.  This is explained in the Quick Start guide Assetic API Access Control.

 

To learn how the script works, see the inline comments as well as the explanations that follow. 

 

  1. """
  2. Example script to apply a work order cost (Assetic.UpdateWorkOrderTask.py)
  3. Applies an actual cost to a work order task
  4. """
  5. import assetic
  6. ##Assetic SDK instance
  7. asseticsdk = assetic.AsseticSDK("c:/users/kwilton/assetic.ini",None,"Info")
  8. ##define work order and task GUID to update against
  9. woguid = "f6a6a21e-0a23-e611-9458-06edd62954d7" #Preview - COMP stage
  10. taskid = "f7a6a21e-0a23-e611-9458-06edd62954d7"
  11. woguid = "46365754-20c3-e611-946c-06edd62954d7" #Demo
  12. taskid = "5a309e65-20c3-e611-946c-06edd62954d7"
  13. ##create work order API instance
  14. wkoapi = assetic.WorkOrderApi()
  15. #get current values for the task. Use this response object as the base
  16. #for the update to ensure fields we are not updating are preserved
  17. try:
  18. task = wkoapi.work_order_get_work_task_by_work_task_id(woguid,taskid)
  19. except assetic.rest.ApiException as e:
  20. asseticsdk.logger.info("Status {0}, Reason: {1}".format(e.status,e.reason))
  21. exit()
  22. #update task object to set external_costs to $500, other costs to $200
  23. task["ParentId"] = woguid
  24. task["ExternalCosts"] = 500
  25. task["OtherCosts"] = 200
  26. ##apply updated task
  27. try:
  28. wkoapi.work_order_put_0(woguid,taskid,task)
  29. except assetic.rest.ApiException as e:
  30. asseticsdk.logger.info("Status {0}, Reason: {1}".format(e.status,e.reason))
  31. else:
  32. asseticsdk.logger.info("Success")

How it Works

The script creates an object instance of the work order task structure by using the Assetic REST SDK to get the work task using the work order GUID and work task GUID.  This example assumes these two values are already known by the integrating application.

The task response has the current values for all fields in the task object. This is important because the PUT api will update all fields, not a subset of fields

try:     task = wkoapi.work_order_get_work_task_by_work_task_id(woguid,taskid)  except assetic.rest.ApiException  as e:     asseticsdk.logger.info("Status {0}, Reason: {1}".format(e.status,e.reason))  exit()

The fields to be updated are changed for the task object.  Note that 'ParentId' (work order GUID) is a mandatory field, but it's value is not returned by the task GET, so it needs to be set.  Only 'External Costs' and 'Othr costs' are being updated in the example.

#update task object to set external_costs to $500, other costs to $200 task["ParentId"]  = woguid task["ExternalCosts"]  =  500 task["OtherCosts"]  =  200

The task object is then passed to the work_order_put_0 method that applies the update.  This method expects 3 parameters, the work order ID, the task Id, and the task object.  Since this method applies an update there is no data returned, just a response code that is handled by assetic.rest.ApiException.  If there is no exception then the update is successful.

 

Note: The Assetic PUT endpoints do not support partial updates so all fields in the payload need to have the updated value, or the original value.  In some instances a GET may be used first to use the response as the basis for the PUT.  The fields to be updated are changed in the response and the response used for the PUT payload.

 

The list of fields that are available in the task object could be listed by creating an instance of the object and listing the 'swagger_types' (swagger is the tool used to produce the SDK)

task = assetic.Assetic3IntegrationApiRepresentationsWorkTask()
print task.swagger_types

You can also use the Python inspect tools to list the methods and objects defined in the assetic SDK.

Creating data

 The Assetic REST API POST endpoints are used to create data.  In the following example a new asset will be created.  

 

  1. """
  2. Create an asset (Assetic.AssetsCreate.py)
  3. """
  4. import assetic
  5. #Define location of configuration file, log file, log level
  6. asseticsdk=assetic.AsseticSDK("C:/users/kwilton/assetic.ini",
  7. None,"Debug")
  8. assetapi = assetic.ComplexAssetApi()
  9. #api has a predefined set of core fields
  10. #can define additional asset attribute fields
  11. #attribute field names are the internal field names, get using metadata api
  12. #create an instance of the complex asset object
  13. asset = assetic.Assetic3IntegrationRepresentationsComplexAssetRepresentation()
  14. ##mandatory fields
  15. asset.asset_category_id='246da33d-6544-e411-82fb-f4b7e2cd8977' #roads
  16. #asset.asset_category = 'Roads'
  17. asset.status = 'Active'
  18. asset.asset_id = 'RINT07'
  19. asset.asset_name = 'Kevin Road 7'
  20. ##optional core fields
  21. asset.asset_class = 'Transport'
  22. asset.asset_sub_class = 'Road'
  23. asset.asset_type = 'Unsealed Road'
  24. asset.asset_sub_type = 'Gravel'
  25. asset.asset_external_identifier = "ext07"
  26. asset.asset_criticality = "Arterial"
  27. asset.asset_maintenance_type = "Road"
  28. asset.asset_maintenance_sub_type = "Arterial Road"
  29. asset.asset_work_group = "Roads"
  30. ##add attributes as a dictionary of field name & field value pairs
  31. asset.attributes = {"Comment":"a comment","Link":"www.assetic.com"}
  32. ##now execute the request
  33. try:
  34. response = assetapi.complex_asset_post(asset)
  35. except assetic.rest.ApiException as e:
  36. asseticsdk.logger.error("Status {0}, Reason: {1}".format(e.status,e.reason))
  37. exit()
  38. if response == None:
  39. asseticsdk.logger.info("Empty response")
  40. exit()
  41. data = response.get("Data")
  42. if data == None:
  43. asseticsdk.logger.info("Asset not created")
  44. exit()
  45. ##display the returned asset data
  46. for newasset in data:
  47. assetid = newasset.get("AssetId")
  48. assetguid = newasset.get("Id")
  49. assetname = newasset.get("AssetName")
  50. msg = "guid: {0}, asset {1}, name {2}".format(
  51. assetguid,assetid,assetname)
  52. ##now get the asset by specifying asset guid
  53. try:
  54. response = assetapi.complex_asset_get(assetguid,["Zone","Locality"])
  55. except assetic.rest.ApiException as e:
  56. asseticsdk.logger.error("Status {0}, Reason: {1}".format(e.status,e.reason))
  57. exit()
  58. if response == None:
  59. asseticsdk.logger.info("Empty response")
  60. exit()
  61. #display the returned info
  62. assetid = response.get("AssetId")
  63. assetguid = response.get("Id")
  64. assetname = response.get("AssetName")
  65. attributes = response.get("Attributes")
  66. zone = attributes.get("Zone")
  67. locality = attributes.get("Locality")
  68. asseticsdk.logger.info("Now get the last asset in the list by asset guid")
  69. msg = "guid: {0}, asset {1}, name {2}, zone {3}, locality {4}".format(
  70. assetguid,assetid,assetname,zone,locality)
  71. asseticsdk.logger.info(msg)
  72. ##get the asset by specifying user friendly asset id
  73. try:
  74. response = assetapi.complex_asset_get(assetid,["Zone","Locality"])
  75. except assetic.rest.ApiException as e:
  76. asseticsdk.logger.error("Status {0}, Reason: {1}".format(e.status,e.reason))
  77. exit()
  78. if response == None:
  79. asseticsdk.logger.info("Empty response")
  80. exit()
  81. #display the returned info
  82. assetid = response.get("AssetId")
  83. assetguid = response.get("Id")
  84. assetname = response.get("AssetName")
  85. attributes = response.get("Attributes")
  86. zone = attributes.get("Zone")
  87. locality = attributes.get("Locality")
  88. msg = "Now get the last asset in the list by user friendly asset ID"
  89. asseticsdk.logger.info(msg)
  90. msg = "guid: {0}, asset {1}, name {2}, zone {3}, locality {4}".format(
  91. assetguid,assetid,assetname,zone,locality)
  92. asseticsdk.logger.info(msg)

Logging to Email

Python allows writing of log output to email via SMTP.  The AssetSDK has an initialisation method that configures this capability on a per script basis.  It requires the SMTP server and credentials to be set in the assetic.ini file.

 

So that a single script does not send multiple emails a log buffer is used to hold the error messages in memory until the user defined 'capacity' (number of log events) is reached.  At that point the messages are written to a single email and sent to one or more recipients.  If 'capacity'=1 then every log event is sent as a separate email.

 

The log level for the emails can be set to a different level to the log file or console output defined when initialising asseticSDK.   If there is an error creating the email then an error is written to the log file/console and no further attempt to email is made for the duration of the script.

The format of the log may also differ from the format output to log file/console.

 

Code Sample

The following code sample initialises email logging at the 'error' level.  This means any error will be sent as an email, but other messages will not.

  1. import assetic
  2. ##initialise the asseticSDK. Standard logging to the console and error level
  3. ##is 'info'
  4. asseticsdk = assetic.AsseticSDK("c:/users/you/assetic.ini",None,"Info")
  5. ##settings for the email logger
  6. loglevel = "Error" #python log level
  7. #set the buffer capacity. In this example on the 10th log 'error' event the
  8. #email is sent with the last 10 errors. If None then defaults to 1
  9. capacity = 10
  10. subject = "Version Integration Error" #subject of email
  11. from_email = "your_email@yourdomain.com"
  12. ##send email to one or more recipients
  13. #to_emails = ["person1@assetic.com","person2@assetic.com"]
  14. to_emails = ["kwilton@assetic.com"]
  15. #can optionally set a different log format to the format used in the log file
  16. #check python docs for formatting options
  17. logformat = "%(asctime)s %(name)-12s %(levelname)-8s %(message)s"
  18. asseticsdk.setup_log_to_email(from_email,to_emails,
  19. subject,capacity,loglevel,logformat)
  20. versionapi = assetic.VersionApi()
  21. try:
  22. asseticsdk.logger.info("Get version information")
  23. response = versionapi.version_get()
  24. except assetic.rest.ApiException as e:
  25. asseticsdk.logger.error("Status {0}, Reason: {1}".format(e.status,e.reason))
  26. else:
  27. asseticsdk.logger.info("{0}.{1}.{2}.{3}".format(response["Major"],response["Minor"],
  28. response["Build"],response["Revision"]))
  29. #the following line is only needed if running from an editor such as IDLE
  30. #and you have initiated email logging with a capcaity > 1
  31. asseticsdk.flush_email_logger()

 

 

Return data in XML format

Instead of the default JSON format, the Assetic REST API response may be returned as XML.  This may be useful if integrating with an application that requires XML data, or perhaps formatting the response into HTML via XSLT style sheets.

To specify a response in XML, instantiate the Assetic Python SDK as normal, and then specify the 'Accepts' header type on the following line as shown below:

##Assetic SDK instance asseticsdk = assetic.AsseticSDK(None,None,"Info")  ##set the response type to XML intead of the default JSON asseticsdk.client.default_headers['Accept']  =  'application/xml'
Note: The response is a string.  To manipulate the XML the string needs to be parsed to XML.  The standard python module ElementTree may be used to do this.

The following code sample is the same as the sample in Getting data from Assetic in this article, however the data is returned as a XML string by the inclusion of the additional line specifying XML as the 'Accept' header.

  1. """
  2. Example script to get work order using guid.
  3. Response data is specified as XML rather than the default JSON
  4. (Assetic.WorkOrderGet_xml.py)
  5. """
  6. import assetic
  7. ##Assetic SDK instance
  8. asseticsdk = assetic.AsseticSDK(None,None,"Info")
  9. ##set the response type to XML intead of the default JSON
  10. asseticsdk.client.default_headers['Accept'] = 'application/xml'
  11. #instance of work order API
  12. wkoapi = assetic.WorkOrderApi()
  13. ##unique ID of work order
  14. woguid = "115ee90b-7ede-4e00-8ad2-0001f6646bab"
  15. try:
  16. wko = wkoapi.work_order_get_0(woguid)
  17. except assetic.rest.ApiException as e:
  18. asseticsdk.logger.error("Status {0}, Reason: {1} {2}".format(
  19. e.status,e.reason,e.body))
  20. else:
  21. ##output the response to the console
  22. print(wko)